深拷贝 浅拷贝

Question 1(基础概念)

请你解释一下:什么是浅拷贝(shallow copy)?什么是深拷贝(deep copy)?它们的核心区别是什么?

 

标准答案(中文)

浅拷贝(shallow copy)和深拷贝(deep copy)的核心区别在于:是否递归复制对象的引用类型属性

1、浅拷贝

浅拷贝只会复制对象的第一层属性,如果属性值是引用类型(对象/数组),复制的是引用地址,而不是值本身。

因此:

2、深拷贝

深拷贝会递归复制对象的所有层级,生成一个完全独立的新对象

因此修改任意层级的数据都不会影响原对象

3、核心区别总结

本质区别是:


✅ Standard Answer (English)

The key difference between shallow copy and deep copy is whether nested reference types are recursively copied or not.

1、Shallow Copy

A shallow copy only copies the first level properties of an object. If a property is a reference type (like an object or array), it copies the reference address instead of the actual value.

So:

2、Deep Copy

A deep copy recursively copies all levels of an object, creating a fully independent clone.

So:

3、Key Difference

 

 

Question 2(Shallow Copy Methods)

请你说一下:在 JavaScript 中,常见的浅拷贝方式有哪些?(至少说出 3 种) Can you list common ways to perform shallow copy in JavaScript? (at least 3 methods)

 

常见浅拷贝方式(JavaScript)

  1. Object.assign()

中文: Object.assign 会创建一个新对象,并把第一层属性复制进去,因此是浅拷贝。

English: Object.assign creates a new object and copies first-level properties into it, making it a shallow copy.


  1. 展开运算符(spread operator)

中文: 展开运算符会复制对象的第一层属性,但嵌套对象仍然是引用。

English: The spread operator copies only the first-level properties, while nested objects are still referenced.


  1. Array 方法(数组浅拷贝)

中文: 这些方法都会生成一个新的数组,但内部元素如果是引用类型,仍然共享。

English: These methods create a new array, but nested reference types are still shared.

 

 

Question 3(Deep Understanding)

为什么 JSON.parse(JSON.stringify(obj)) 可以实现深拷贝?它有什么缺陷? Why can JSON.parse(JSON.stringify(obj)) achieve deep copy? What are its limitations?

 

问题一:

中文解释

这个方法的本质是:

先把对象转成 JSON 字符串,再重新解析成一个新对象

过程是:

  1. JSON.stringify(obj) 👉 把 JS 对象“序列化”为字符串(会丢失引用关系)
  2. JSON.parse(...) 👉 再把字符串解析成一个全新的对象

✔ 所以它天然“断开引用”,实现类似深拷贝效果

 

English explanation

The idea is:

Convert the object into a JSON string, then parse it back into a new object.

Steps:

  1. JSON.stringify(obj) serializes the object into a string, removing references.
  2. JSON.parse(...) creates a completely new object from that string.

✔ This breaks reference links, which makes it behave like a deep copy.

 

问题二:

中文答案,这个比较多,看一下理解即可:

  1. 不能拷贝函数

👉 会被直接忽略

  1. 不能拷贝 undefined / Symbol

👉 会丢失

  1. 不能处理循环引用(会报错)

👉 会直接报错:

Converting circular structure to JSON

  1. 会丢失特殊对象类型

比如:

 

英文回答:

 

Question 4

你能手写一个“完整支持对象 + 数组 + 循环引用”的深拷贝吗?思路是什么?

Can you implement a deep clone function that supports objects, arrays, and circular references? What is your approach?

 


先讲思路:

实现深拷贝的核心是三件事:

1️⃣ 判断类型

区分:

2️⃣ 区分对象和数组

3️⃣ 解决循环引用(重点)

用一个结构记录“已经拷贝过的对象”:

👉 MapWeakMap

作用:

防止对象无限递归

 

Core idea

To implement deep clone, we need to:

  1. Return primitive values directly
  2. Recursively copy objects and arrays
  3. Track visited objects to handle circular references

Key technique: WeakMap

We use WeakMap to store already cloned objects:


代码:

 

ES6 新特性

Question 1(基础)

##

你能说一下 ES6 你最常用的几个新特性有哪些吗?(至少说 3 个) What are some ES6 features you commonly use? (at least 3)

 

中文

我常用的 ES6 特性有:

  1. let / const:用于块级作用域,避免变量提升带来的问题
  2. 箭头函数:简化函数写法,并且没有自己的 this
  3. 解构赋值:可以方便地从对象或数组中提取数据
  4. 模块化(import / export):用于代码拆分和复用

English

Some ES6 features I frequently use include:

  1. let / const for block scoping and avoiding hoisting issues
  2. Arrow functions for concise syntax and lexical this
  3. Destructuring for extracting values from objects and arrays
  4. ES Modules (import / export) for better code organization

Question 2(this + 箭头函数)

箭头函数和普通函数的 this 有什么区别? What is the difference between this in arrow functions and regular functions?

 

中文高分表达

箭头函数和普通函数最大的区别在于 this 的绑定方式不同。 普通函数的 this 是在调用时决定的,取决于调用方式; 而箭头函数没有自己的 this,它的 this 是在定义时就确定的,会继承外层作用域的 this。

English 口语版

The main difference is how this is determined. For regular functions, this is decided at call time depending on how the function is invoked. For arrow functions, this is lexically bound, meaning it is determined at definition time and inherited from the outer scope.

 

Question 3(进阶)

箭头函数为什么不能作为构造函数? Why can't arrow functions be used as constructors?

 

中文

箭头函数不能作为构造函数,主要有两个原因:

1️⃣ 没有 prototype

👉 构造函数必须有 prototype,用于实例继承

 

2️⃣ 没有自己的 this

箭头函数的 this继承外层作用域的

👉 但构造函数需要一个新的 this(指向实例)

❗ 直接结果

👉 会报错:

Person is not a constructor

 

✅ 一句话总结(面试必杀)

箭头函数不能作为构造函数,因为它没有 prototype,并且没有自己的 this


✅ English Version

Arrow functions cannot be used as constructors for two main reasons:

  1. No prototype

Constructors must have a prototype for instances to inherit from.

 

  1. No own this

Arrow functions do not have their own this; they inherit this from the outer scope.

👉 But constructors require a new this bound to the instance.

Result

Person is not a constructor

 

 

Question 4(陷阱题)

箭头函数有没有 arguments?如果没有,怎么获取参数? Do arrow functions have arguments? If not, how can you access arguments?

 

✅ 一句话总结(面试用)

箭头函数没有自己的 arguments,它会继承外层作用域的 arguments,通常用 ...args 来获取参数

✅ English Version

👉 No, arrow functions do not have their own arguments object.

They inherit arguments from the outer scope.

 

那么如何获取参数呢?使用...args来获取:

How to access arguments?

👉 Use rest parameters:

Key takeaway

Arrow functions don’t have their own arguments; use rest parameters instead.


案例说明:

👉 Output:

 

 

Question 5(解构赋值进阶)

解构赋值有哪些常见用法?以及它有哪些坑点? What are common use cases of destructuring, and what are its pitfalls?

 

English

Common use cases:

坑点:

解构赋值我在使用中主要注意几个点: 第一,默认值只在属性是 undefined 的时候才生效,如果是 null 是不会触发默认值的。 第二,如果对 null 或 undefined 进行解构会直接报错,所以一般会加一个兜底,比如用 || {} 第三,嵌套解构的时候,如果中间某一层是 undefined,也会报错,需要给默认值。 还有一个是,数组解构是按顺序来的,对象解构是按 key 来的,这一点要区分。

✅ English(面试版)

When using destructuring, there are a few important pitfalls: First, default values only work when the value is undefined, not null. Second, destructuring null or undefined will throw an error, so we usually provide a fallback like || {}. Third, nested destructuring can fail if an intermediate property is undefined, so we need default values there. Also, array destructuring is position-based, while object destructuring is key-based.


深入理解:

1、常见用法

1️⃣ 对象解构

2️⃣ 数组解构

3️⃣ 函数参数解构

2、坑点

🧠 坑 1:默认值只在 undefined 时生效

👉 不会使用默认值

✅ 结论

默认值只在属性为 undefined 时才生效

English

Default values only apply when the value is undefined, not null.


🧠 坑 2:解构 null / undefined 会直接报错

✅ 解决方案

English

Destructuring null or undefined will throw an error.

Solution:


🧠 坑 3:嵌套解构容易报错

👉 如果 a 是 undefined → 直接崩

✅ 安全写法


🧠 坑 4:变量重命名

👉 不是赋值,而是重命名


🧠 坑 5:数组解构是按位置,不是按名字

👉 顺序非常重要

 

Question 6(正式开始)

扩展运算符(...)和 rest 参数有什么区别? What is the difference between the spread operator and rest parameters?

 

中文

你可以这样说:

扩展运算符和 rest 参数本质上是同一个语法 ...,但使用场景不同。

spread 是用来“展开”的,比如把数组或对象拆开,用在赋值或者函数调用的时候。

rest 是用来“收集”的,比如在函数参数中,把多个参数收集成一个数组。

一个是往外展开,一个是往里收集。

English

Spread and rest use the same syntax ..., but they serve different purposes.

Spread is used to expand values, like spreading an array or object.

Rest is used to collect values, usually in function parameters.

One expands, the other collects.

 

 

Question 7(new 核心)

new 关键字在 JavaScript 中做了什么? What does the new keyword do in JavaScript?

 

中文

new 关键字在 JavaScript 中主要做了四件事。

第一,它会创建一个新的空对象。 第二,它会把这个新对象的原型指向构造函数的 prototype。 第三,它会把构造函数内部的 this 绑定到这个新对象上。 第四,如果构造函数没有显式返回对象,就默认返回这个新对象。

✅ English version

The new keyword in JavaScript performs four steps:

First, it creates a new empty object. Second, it sets the object's prototype to the constructor's prototype. Third, it binds this inside the constructor to the new object. Fourth, it returns the object unless the constructor explicitly returns another object.


方便记忆:

new = 创建对象 + 绑定 this + 继承 prototype + 返回对象

 

Question 8 (手写 new)

Can you implement the new operator manually? 你能手写 new 的实现吗?

 

 

中文

new 的实现本质是四步: 首先创建一个空对象,然后把它的原型指向构造函数的 prototype, 接着把构造函数的 this 绑定到这个对象上并执行, 最后如果构造函数返回的是对象就返回它,否则返回这个新对象。

English

The implementation of new involves four steps: First, create a new empty object. Then set its prototype to the constructor's prototype. Next, bind this of the constructor to the new object and execute it. Finally, return the object if the constructor returns one; otherwise return the newly created object.